package com.cvte.boe.media.player;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.media.MediaPlayer;
import android.media.TimedText;
import android.os.Handler;
import android.os.Message;
import android.os.Parcel;
import android.util.DisplayMetrics;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;

import com.cvte.boe.media.R;
import com.cvte.boe.media.controller.MediaFileManager;
import com.cvte.boe.media.dao.MediaSettingDao;
import com.cvte.boe.media.dao.MediaSettingDaoImpl;
import com.cvte.boe.media.model.LocalMediaInfo;
import com.cvte.boe.media.utils.LogUtil;
import com.cvte.boe.media.utils.OrientationUtil;
import com.cvte.boe.media.utils.SettingUtil;
import com.cvte.boe.media.utils.StringUtils;
import com.cvte.boe.media.utils.constant.Constant;
import com.cvte.boe.media.utils.hisilicon.HiMediaPlayer;
import com.cvte.boe.media.utils.hisilicon.HiMediaPlayerInvoke;
import com.cvte.boe.media.views.AutoHideLayout;
import com.cvte.boe.media.views.widget.MarqueeTextView;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by wuguitong on 2018/4/19.
 */
public class VideoPlayer implements MediaPlayer.OnPreparedListener,MediaPlayer.OnCompletionListener,MediaPlayer.OnErrorListener,
        MediaPlayer.OnInfoListener,MediaPlayer.OnSeekCompleteListener,MediaPlayer.OnVideoSizeChangedListener,MediaPlayer.OnTimedTextListener{
    private enum VideoStatus{
        UNKNOW,PREPAREING,INITED,PLAYING,PAUSE,SEEKING,SEEKEND,STOPPED
    }
    private static final int MIN_BACKWARD_FORWARD_TIME = 1000;
    private static final int SEEKBAR_STEP_COUNT = 25;
    private static final int MSG_VIDEO_INITED = 0;
    private static final int MSG_VIDEO_END = 1;
    private static final int MSG_UPDATE_PLAYINFO = 2;
    private static final int MSG_UPDATE_TOP_BAR= 3;
    private static final int MSG_UPDATE_BOTTOM_BAR= 4;
    private static final int MSG_VIDEO_NOT_SUPPORT= 5;
    private static final int MSG_DISMISS_SUBTITLE = 100;
    private static final int TIME_DISMISS_SUBTITLE = 5000;
    private static final String TAG = VideoPlayer.class.getSimpleName();
    private final static String IMEDIA_PLAYER = "android.media.IMediaPlayer";
    private static final int TIME_UPDATE_PLAYINFO = 5 * 100;
    public static MediaPlayer mPlayer = null; // cvte shiqiankun @ 20151222 add
    public String[] mSubFormat = {"ASS", "LRC", "SRT", "SMI", "SUB", "TXT", "PGS", "DVB", "DVD"};
    private Context mContext;
    private AutoHideLayout ahTopBar;
    private AutoHideLayout ahBottomBar;
    private MarqueeTextView mTVName;
    private SeekBar mVideoSeebar;
    private TextView mTvCurTime;
    private TextView mTvTotalTime;
    private SurfaceView mSurfaceView;
    private SurfaceView mSubtitleSurfaceView;
    private TextView mSubtitleTextView;
    private ImageView mStatusImageView;
    private List<LocalMediaInfo> mLocalMediaInfoList;
    private String mCurrentFileName;
    private int mCurrentFileIndex;
    private SurfaceHolder mSurfaceHolder = null;
    private final Object mutex = new Object();
    private SettingUtil.VLOOP mCurLoop;
    private SettingUtil.VDISPLAY mCurDisplay;
    private SettingUtil.VAUDIO mCurAudio;
    private SettingUtil.VSUBTITLE mCurSubtitle;
    private VideoStatus mVideoStatus = VideoStatus.UNKNOW;
    private OnVideoPlayerListoner listoner = null;
    public interface OnVideoPlayerListoner{
        void OnVideoPlayerInited();
        void OnVideoUnsupport();
    }
    public void setOnVideoPlayerListener(OnVideoPlayerListoner listener){
        this.listoner = listener;
    }
    private Handler dismissHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_DISMISS_SUBTITLE:
                    if(mSubtitleTextView != null){
                        mSubtitleTextView.setText("");
                        mSubtitleTextView.setVisibility(View.GONE);
                    }
                    break;
                default:
                    break;
            }
        }
    };
    private Handler videoHander = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_VIDEO_INITED:
                    if(mVideoStatus == VideoStatus.PREPAREING) {
                        mVideoStatus = VideoStatus.INITED;
                        if(listoner != null){
                            listoner.OnVideoPlayerInited();
                        }
                        mPlayer.start();
                        setVideoSub(mCurSubtitle);
                        videoHander.removeMessages(MSG_UPDATE_PLAYINFO);
                        videoHander.sendEmptyMessage(MSG_UPDATE_PLAYINFO);
                        mVideoSeebar.setMax(mPlayer.getDuration());
                        mVideoStatus = VideoStatus.PLAYING;
                    }
                    break;
                case MSG_VIDEO_END:
                    mVideoStatus = VideoStatus.STOPPED;
                    mVideoSeebar.setProgress(mPlayer.getDuration());
                    videoHander.removeMessages(MSG_UPDATE_PLAYINFO);
                    playNextVideo();
                    break;
                case MSG_UPDATE_PLAYINFO:
                    if(mPlayer != null && mVideoStatus.ordinal() >= VideoStatus.PLAYING.ordinal() && mVideoStatus.ordinal() < VideoStatus.STOPPED.ordinal()) {
                        int dur = mPlayer.getDuration();
                        int cur = mPlayer.getCurrentPosition();
                        LogUtil.d(TAG,"cur = " + cur + " dur = " + dur + "mVideoStatus = " + mVideoStatus.toString());
                        mTvTotalTime.setText(StringUtils.formatMediaTimeToString(dur));
                        mTvCurTime.setText(StringUtils.formatMediaTimeToString(cur));
                        mVideoSeebar.setProgress(cur);
                        if(mVideoStatus == VideoStatus.PLAYING) {
                            videoHander.sendEmptyMessageDelayed(MSG_UPDATE_PLAYINFO, TIME_UPDATE_PLAYINFO);
                        }
                        if(mVideoStatus == VideoStatus.SEEKEND){
                            mVideoSeebar.setProgress(dur);
                        }
                    }
                    break;
                case MSG_UPDATE_TOP_BAR:
                    ahTopBar.show();
                    break;
                case MSG_UPDATE_BOTTOM_BAR:
                    ahBottomBar.show();
                    break;
                case MSG_VIDEO_NOT_SUPPORT:
                    mPlayer.pause();
                    new AlertDialog.Builder(mContext).setTitle(R.string.video_info_system_prompt)
                            .setMessage(R.string.video_info_video_unsupport)
                            .setPositiveButton(R.string.btn_text_ok, new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialogInterface, int i) {
                                    if(listoner != null){
                                        listoner.OnVideoUnsupport();
                                    }
                                }
                            }).setCancelable(false).show();
                    break;
                default:
                    break;
            }
        }
    };

    public void initPlayer(Context context, String fileName, String dir, AutoHideLayout top, AutoHideLayout bottom, MarqueeTextView name,
                           TextView curTime, TextView totalTime,SeekBar videoSeebar, SurfaceView surfaceView, TextView subtitleText, ImageView statusImageView){
        if(mPlayer == null){
            mPlayer = new MediaPlayer();
        }
        mPlayer.setOnPreparedListener(this);
        mPlayer.setOnCompletionListener(this);
        mPlayer.setOnErrorListener(this);
        mPlayer.setOnInfoListener(this);
        mPlayer.setOnSeekCompleteListener(this);
        mPlayer.setOnVideoSizeChangedListener(this);
        mVideoStatus = VideoStatus.PREPAREING;
        this.mContext = context;
        this.mCurrentFileName = fileName;
        this.ahTopBar = top;
        this.ahBottomBar = bottom;
        this.mTVName = name;
        this.mTvCurTime = curTime;
        this.mTvTotalTime = totalTime;
        this.mSurfaceView = surfaceView;
        this.mSubtitleTextView = subtitleText;
        this.mStatusImageView = statusImageView;
        this.mVideoSeebar = videoSeebar;
        this.mLocalMediaInfoList = new ArrayList<>();
        this.mVideoSeebar.setFocusable(false);
        this.mLocalMediaInfoList.addAll(MediaFileManager.getInstance().getMediaFilesByType(dir, Constant.MediaType.VIDEO));
        MediaSettingDao dao  = new MediaSettingDaoImpl(mContext);
        mCurAudio = dao.getVideoAudio();
        mCurLoop = dao.getVideoLoop();
        mPlayer.setLooping(mCurLoop == SettingUtil.VLOOP.SINGLECYCLE);
        mCurDisplay = dao.getVideoDisplay();
        mCurSubtitle = dao.getVideoSubtitle();
        mCurrentFileIndex = -1;
        int index = 0;
        for(LocalMediaInfo m : mLocalMediaInfoList){
            if(m.getFileAllName().equals(mCurrentFileName)){
                mCurrentFileIndex = index;
                break;
            }
            index++;
        }
        if((mLocalMediaInfoList.size()) > 0 && (mCurrentFileIndex == -1)) {
            mCurrentFileIndex = 0;
            mCurrentFileName = mLocalMediaInfoList.get(mCurrentFileIndex).getFileAllName();
        }
        mSurfaceHolder = surfaceView.getHolder();
        mSurfaceHolder.addCallback(mSHCallback);
        ahTopBar.show();
        mTVName.setText(mLocalMediaInfoList.get(mCurrentFileIndex).getFileName());
    }
    public void deinitVideoPlayer(){
        videoHander.removeMessages(MSG_UPDATE_PLAYINFO);
        videoHander.removeMessages(MSG_VIDEO_INITED);
        videoHander.removeMessages(MSG_VIDEO_END);
        videoHander.removeMessages(MSG_VIDEO_NOT_SUPPORT);
        videoHander.removeMessages(MSG_UPDATE_BOTTOM_BAR);
        videoHander.removeMessages(MSG_UPDATE_TOP_BAR);
        dismissHandler.removeMessages(MSG_DISMISS_SUBTITLE);
        if(mPlayer != null) {
            mPlayer.stop();
            mPlayer.release();
            mPlayer = null;
            mVideoStatus = VideoStatus.UNKNOW;
        }
    }
    SurfaceHolder.Callback mSHCallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder surfaceHolder) {
            if(mPlayer ==  null){
                mPlayer = new MediaPlayer();
            }
            mPlayer.setDisplay(surfaceHolder);
            mPlayer.setScreenOnWhilePlaying(true);
            try {
                mPlayer.setDataSource(mCurrentFileName);
                mPlayer.prepareAsync();
            } catch (IOException e) {
                mVideoStatus = VideoStatus.UNKNOW;
                e.printStackTrace();
            }

        }

        @Override
        public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
            LogUtil.d(TAG,"surfaceChanged");
        }

        @Override
        public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
            LogUtil.d(TAG,"surfaceDestroyed");
        }
    };

    @Override
    public void onCompletion(MediaPlayer mediaPlayer) {
        LogUtil.d(TAG,"onCompletion");
        if(mCurLoop == SettingUtil.VLOOP.FULLCYCLE){
            if(!mPlayer.isLooping()){
                videoHander.sendEmptyMessage(MSG_VIDEO_END);
            }
        }
    }

    @Override
    public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
        LogUtil.d(TAG,"MediaPlayer onError");
        return false;
    }

    @Override
    public void onSeekComplete(MediaPlayer mediaPlayer) {
        LogUtil.d(TAG,"onSeekComplete");
        mStatusImageView.setVisibility(View.GONE);
        if(mVideoStatus == VideoStatus.SEEKEND){
            videoHander.removeMessages(MSG_UPDATE_PLAYINFO);
        }else {
            mPlayer.start();
            mVideoStatus = VideoStatus.PLAYING;
            restartUpdatePlayInfo();
        }
    }

    @Override
    public void onVideoSizeChanged(MediaPlayer mediaPlayer, int i, int i1) {
        LogUtil.d(TAG,"onVideoSizeChanged");
        changeVideoSize(mCurDisplay);
    }

    @Override
    public boolean onInfo(final MediaPlayer mp, final int what, final int extra) {
        LogUtil.d(TAG,"Infowhat:" + what + "  extra:" + extra);
        switch (what){
            case HiMediaPlayer.MEDIA_INFO_VIDEO_FAIL:
                videoHander.sendEmptyMessage(MSG_VIDEO_NOT_SUPPORT);
                break;
            default:
                break;
        }
        return false;
    }

    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        LogUtil.d(TAG,"onPrepared");
        videoHander.sendEmptyMessage(MSG_VIDEO_INITED);
        mPlayer.setOnTimedTextListener(this);
    }

    @Override
    public void onTimedText(MediaPlayer mediaPlayer, TimedText timedText) {
        if(mSubtitleTextView != null && timedText != null) {
            dismissHandler.removeMessages(MSG_DISMISS_SUBTITLE);
            mSubtitleTextView.setVisibility(View.VISIBLE);
            mSubtitleTextView.setText(timedText.getText());
            dismissHandler.sendEmptyMessageDelayed(MSG_DISMISS_SUBTITLE,TIME_DISMISS_SUBTITLE);
        }
    }

    private void playNextVideo(){
        mCurrentFileIndex++;
        if(mCurrentFileIndex == mLocalMediaInfoList.size()){
            mCurrentFileIndex = 0;
        }
        mCurrentFileName = mLocalMediaInfoList.get(mCurrentFileIndex).getFileAllName();
        mVideoStatus = VideoStatus.PREPAREING;
        mTVName.setText(mLocalMediaInfoList.get(mCurrentFileIndex).getFileName());
        LogUtil.d(TAG,"playNextVideo " + mLocalMediaInfoList.get(mCurrentFileIndex).getFileName());
        try {
            mPlayer.reset();
            mPlayer.setDataSource(mCurrentFileName);
            mPlayer.prepareAsync();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public int disableSubtitle(int disable) {
        if (mPlayer != null) {
            return disableSubtitleInvoke(disable);
        }

        return -1;
    }
    public int disableSubtitleInvoke(int disable) {
        int flag = HiMediaPlayerInvoke.CMD_SET_SUB_DISABLE;

        return excuteCommand(flag, disable, false);
    }
    public boolean isSubtitleEnable() {
        int flag = HiMediaPlayerInvoke.CMD_GET_SUB_DISABLE;
        int rslt = excuteCommand(flag, 0, true);
        return (rslt <= 0);
    }
    public List<String> getInternalSubtitleLanguageInfoList() {
        if (mPlayer != null) {
            Parcel _Request = Parcel.obtain();
            Parcel _Reply = Parcel.obtain();

            _Request.writeInterfaceToken(IMEDIA_PLAYER);
            _Request.writeInt(HiMediaPlayerInvoke.CMD_GET_SUB_INFO);

            invoke(_Request, _Reply);

            List<String> _LanguageList = new ArrayList<String>();

            //for get
            _Reply.readInt();
            int _Num = _Reply.readInt();
            String _Language = "";
            String _SubFormat = "";
            String _SubName = "";
            int _IsExt = 0;

            for (int i = 0; i < _Num; ++i) {
                _Reply.readInt();
                _IsExt = _Reply.readInt();
                _Language = _Reply.readString();
                _SubFormat = mSubFormat[_Reply.readInt()];
                if (_Language == null || _Language.equals("-")) {
                    _Language = "";
                }

                _SubName = mContext.getString(R.string.subtitle) + (i + 1);
                _LanguageList.add(_SubName);

            }

            _Request.recycle();
            _Reply.recycle();

            return _LanguageList;
        }

        return new ArrayList<String>();
    }

    public int getSubtitleCount() {
        return getInternalSubtitleLanguageInfoList().size();
    }

    public int getsubtitleId() {
        if (mPlayer != null) {
            Parcel Request = Parcel.obtain();
            Parcel Reply = Parcel.obtain();

            Request.writeInterfaceToken(IMEDIA_PLAYER);
            Request.writeInt(HiMediaPlayerInvoke.CMD_GET_SUB_ID);

            invoke(Request, Reply);

            Reply.readInt();
            int Result = Reply.readInt();

            Request.recycle();
            Request.recycle();

            return Result;
        }

        return -1;
    }

    public int setSubtitleId(int pSubtitleId) {
        if (mPlayer != null) {
            return setSubTrack(pSubtitleId);
        }
        return -1;
    }

    private int setSubTrack(int track) {
        int flag = HiMediaPlayerInvoke.CMD_SET_SUB_ID;

        return excuteCommand(flag, track, false);
    }

    public void invoke(Parcel request, Parcel reply) {
        if (mPlayer != null) {
            /*Add catch because DPT don't support setVideoCvrs function*/
            /*and SDK don't support setNewFounction*/
            try {
                Method invoke = mPlayer.getClass().getDeclaredMethod("invoke",new Class[]{Parcel.class, Parcel.class});
                invoke.invoke(mPlayer, request, reply);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    private int excuteCommand(int pCmdId, int pArg, boolean pIsGet) {
        Parcel Request = Parcel.obtain();
        Parcel Reply = Parcel.obtain();

        Request.writeInterfaceToken(IMEDIA_PLAYER);
        Request.writeInt(pCmdId);
        Request.writeInt(pArg);

        invoke(Request, Reply);

        if (pIsGet) {
            Reply.readInt();
        }

        int Result = Reply.readInt();

        Request.recycle();
        Reply.recycle();

        return Result;
    }
    public boolean setVideoLoop(SettingUtil.VLOOP loop){
        if(mCurLoop != loop) {
            if(mVideoStatus.ordinal() >= VideoStatus.INITED.ordinal() && mVideoStatus.ordinal() < VideoStatus.STOPPED.ordinal()) {
                mCurLoop = loop;
                mPlayer.setLooping(loop == SettingUtil.VLOOP.SINGLECYCLE);
                return true;
            }
        }
        return false;
    }
    public boolean setVideoSub(SettingUtil.VSUBTITLE sub){
        if(sub != mCurSubtitle){
            if(mVideoStatus.ordinal() >= VideoStatus.INITED.ordinal() && mVideoStatus.ordinal() < VideoStatus.STOPPED.ordinal()) {
                mCurSubtitle = sub;
                if(mCurSubtitle == SettingUtil.VSUBTITLE.OFF){
                    disableSubtitle(1);
                }else{
                    disableSubtitle(0);
                    setSubTrack(0);
                }
                return true;
            }
        }
        return false;
    }
    public boolean setVideoAudio(SettingUtil.VAUDIO audio){
        if(audio != mCurAudio){
            if(mVideoStatus.ordinal() >= VideoStatus.INITED.ordinal() && mVideoStatus.ordinal() < VideoStatus.STOPPED.ordinal()) {
                return true;
            }
        }
        return false;
    }
    public boolean setVideoDisplay(SettingUtil.VDISPLAY display){
        if(display != mCurDisplay){
            if(mVideoStatus.ordinal() >= VideoStatus.INITED.ordinal() && mVideoStatus.ordinal() < VideoStatus.STOPPED.ordinal()) {
                mCurDisplay = display;
                changeVideoSize(display);
                return true;
            }
        }
        return false;
    }

    public void showTopName(){
        videoHander.sendEmptyMessage(MSG_UPDATE_TOP_BAR);
    }
    public void showBottomBar(){
        videoHander.sendEmptyMessage(MSG_UPDATE_BOTTOM_BAR);
    }

    public void changeVideoPlayStatus(){
        LogUtil.d(TAG,"changeVideoPlayStatus");
        if(mPlayer != null){
            if(mPlayer.isPlaying()){
                mVideoStatus = VideoStatus.PAUSE;
                mPlayer.pause();
                mStatusImageView.setVisibility(View.VISIBLE);
            }else{
                mVideoStatus = VideoStatus.PLAYING;
                mStatusImageView.setVisibility(View.GONE);
                mPlayer.start();
            }
            restartUpdatePlayInfo();
            showTopName();
            showBottomBar();
        }
    }
    public void backwardVideo(){
        mVideoStatus = VideoStatus.SEEKING;
        int dur = mPlayer.getDuration();
        int cur = mPlayer.getCurrentPosition();
        int time = dur / SEEKBAR_STEP_COUNT;
        int newPos = 0;
        if(time < MIN_BACKWARD_FORWARD_TIME){
            newPos = cur - MIN_BACKWARD_FORWARD_TIME;
        }else{
            newPos = cur - time;
        }
        if(newPos < 0){
            newPos = 0;
        }
        mPlayer.seekTo(newPos);
        restartUpdatePlayInfo();
        showTopName();
        showBottomBar();
    }
    public void forwardVideo(){
        if(mVideoStatus == VideoStatus.PLAYING || mVideoStatus == VideoStatus.SEEKEND || mVideoStatus == VideoStatus.PAUSE) {
            mVideoStatus = VideoStatus.SEEKING;
            int dur = mPlayer.getDuration();
            int cur = mPlayer.getCurrentPosition();
            int time = dur / SEEKBAR_STEP_COUNT;
            int newPos = 0;
            if (time < MIN_BACKWARD_FORWARD_TIME) {
                newPos = cur + MIN_BACKWARD_FORWARD_TIME;
            } else {
                newPos = cur + time;
            }
            if (newPos > dur) {
                mVideoStatus = VideoStatus.SEEKEND;
                newPos = dur;
            }
            mPlayer.seekTo(newPos);
            restartUpdatePlayInfo();
            showTopName();
            showBottomBar();
        }
    }
    private void restartUpdatePlayInfo(){
        if(videoHander.hasMessages(MSG_UPDATE_PLAYINFO)){
            videoHander.removeMessages(MSG_UPDATE_PLAYINFO);
        }
        videoHander.sendEmptyMessage(MSG_UPDATE_PLAYINFO);
    }

    public void changeVideoSize(SettingUtil.VDISPLAY vdisplay) {
        if (vdisplay == SettingUtil.VDISPLAY.AUTOSCREEN) {
            int videoWidth = mPlayer.getVideoWidth();
            int videoHeight = mPlayer.getVideoHeight();
            DisplayMetrics dm = new DisplayMetrics();
            ((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
            int surfaceWidth = dm.widthPixels;
            int surfaceHeight = dm.heightPixels;

            LogUtil.d(TAG, " " + videoHeight + " " + videoWidth + " " + surfaceHeight + " " + surfaceWidth);

            //根据视频尺寸去计算->视频可以在sufaceView中放大的最大倍数。
            float max;
            if (OrientationUtil.isLandscapeOrientation(mContext)) {
                //横屏模式下按视频高度计算放大倍数值
                max = Math.max(((float) videoWidth / (float) surfaceWidth), (float) videoHeight / (float) surfaceHeight);
            } else {
                //竖屏模式下按视频宽度计算放大倍数值
                max = Math.max((float) videoWidth / (float) surfaceWidth, (float) videoHeight / (float) surfaceHeight);
            }
            //视频宽高分别/最大倍数值 计算出放大后的视频尺寸
            videoWidth = (int) Math.ceil((float) videoWidth / max);
            videoHeight = (int) Math.ceil((float) videoHeight / max);

            //无法直接设置视频尺寸，将计算出的视频尺寸设置到surfaceView 让视频自动填充。
            mSurfaceView.setLayoutParams(new RelativeLayout.LayoutParams(videoWidth, videoHeight));
        } else {
            mSurfaceView.setLayoutParams(new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
        }
    }
}
